package com.finch.juc;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @author Levi Wang
 * @create 2021-07-10 10:47
 *
 * 题目：请举例说明集合类是不安全的
 *
 * 面试官：
 * 1、讲出你见过的5个Java异常，
 * java.util.ConcurrentModificationException是一个不错的选择
 * 2、平时工作学习中有没有遇到过List、Set或者Map线程不安全的问题？报的是什么错？你是怎么解决的？
 *HashSet、HashMap都是线程不安全的, 其底层都是如何实现的？
 * HashSet的底层是HashMap，为什么add方法数量对不上；HashSet的add底层是HashMap的put方法
 * ArrayList（扩容一半） 有序 有重复
 * HashSet、HashMap 无序，无重复
 * 3、请说一下HashMap（扩容一倍）的底层数据结构
 *
 *
 *
 * 金句：
 * 1、我今天不是去面试的，我是去谈合作的
 * 2、此处不留爷，自有留爷处
 *
 *
 * 用ArrayList，30次
 * 1、故障现象
 * java.util.ConcurrentModificationException 并发修改异常
 *
 * 2、导致原因
 *
 *
 * 3、解决方案
 *  3.1  用Vector （不建议使用）  能保证数据一致性  性能差
 *  3.2  用Collections.synchronizedList(new ArrayList<>())
 *  3.3  用new CopyOnWriteArrayList<>()   写时复制，基于读写分离思想；看源码了解清楚是怎么实现的，尤其是其add方法的源码（参考原资料详细笔记）
 *
 * 4、优化建议（同样的错误，不出现第二次）
 *
 *
 *
 *
 *HashSet 30次
 * 报错：java.util.ConcurrentModificationException
 *
 *
 *
 */

public class NotSafeDm {

    public static void main(String[] args) {

//        listNotSafe();
//        setNotSafe();

//        Map<String, String> map = new HashMap<>(); //默认 16  0.75

//        Map<String, String> map = Collections.synchronizedMap(new HashMap<>());

        Map<String, String> map = new ConcurrentHashMap<>();

        for (int i = 1; i <= 30; i++) {

            new Thread(() -> {
                //工具
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }

    }

    private static void setNotSafe() {
        //        Set<String> set = new HashSet<>();

//        Set<String> set = Collections.synchronizedSet(new HashSet<>());

        Set<String> set = new CopyOnWriteArraySet<>();

        for (int i = 1; i <= 30; i++) {

            new Thread(() -> {
                //工具
                set.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }
    }


    public static void listNotSafe() {
        //方法引用
//        List<String> list = Arrays.asList("a", "b", "c");
//        list.forEach(System.out::println);


//        List<String> list = new ArrayList<>();

        //Vector是线程安全的，可以看他的add方法，有一个synchronized锁；而ArrayList没有
        //线程安全能保证数据一致性，但是读取效率会下降。访问性能下降
//        List<String> list = new Vector<>();

//        List<String> list = Collections.synchronizedList(new ArrayList<>());

        List<String> list = new CopyOnWriteArrayList<>();


/*        //这面这种写法跟上面效果一样，但是太麻烦
        list.add("a");
        list.add("b");
        list.add("c");
        for(String element : list){
            System.out.println(element);
        }*/

        //3次不会出错，但是30次会报错
        for (int i = 1; i <= 30; i++) {

            new Thread(() -> {
                //工具
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }

}
